<?php
/**
 * workman 长链接
 * php think worker:server (-d linux下守护进程)
 */

namespace app\server;


use app\model\MasterModel;
use think\exception\ErrorException;
use think\worker\Server;
use Workerman\Lib\Timer;

class Work extends Server {

    protected $socket = 'http://0.0.0.0:9151';
    protected $heartTime = 50;

    public function __construct() {
        parent::__construct();
    }

    // 新增加一个属性，用来保存uid到connection的映射
    public static $uidConnections = [];
    public static $master = [];

    public function onWorkerStart($worker) {
        dump('开始');
//        Timer::add(10, function () use ($worker) {
//            $time_now = time();
//            foreach ($worker->connections as $connection) {
//                // 有可能该connection还没收到过消息，则lastMessageTime设置为当前时间
//                if (empty($connection->lastMessageTime)) {
//                    $connection->lastMessageTime = $time_now;
//                    continue;
//                }
//                // 上次通讯时间间隔大于心跳间隔，则认为客户端已经下线，关闭连接
//                if ($time_now - $connection->lastMessageTime > $this->heartTime) {
//                    $connection->close();
//                }
//            }
//        });
//        Timer::add(30, function () use ($worker) {
//            MasterModel::cursor();
//        });

    }

    /**
     * 有用户连接时
     * @param $connection
     */
    public function onConnect($connection) {
        $this->sendOnline();
    }

    /**
     * 接收到客户端信息时
     * @void type 请求类型，0保持连接 1初始连接登录，2发送消息
     * @param $connection
     * @param $data
     */
    public function onMessage($connection, $data) {
        if ($data) {
            $data = json_decode($data, true);
            // 判断当前客户端是否已经验证,既是否设置了uid
            switch ($data['type']) {
                case 0:
                    break;
                case 1:
                    if (!isset($connection->uid)) {//连接未设置uid
                        $info = verifyJwt($data['token']);
                        if ($info['code'] == 1) {
                            $connection->uid = $info['data']['uid'];
                            /* 保存uid到connection的映射，这样可以方便的通过uid查找connection，
                             * 实现针对特定uid推送数据
                             */
                            self::$uidConnections[$connection->uid] = $connection;
                        } else {
                            $connection->send(json_encode(['type' => 3]));
                        }
                    }
                    break;
                case 2:
                    $msgData = [
                        'uid' => $connection->uid,
                        'to_id' => $data['to_id'],
                        'msg' => $data['data'],
                        'time' => time()
                    ];
                    $msgData['time'] = date('Y-m-d H:i:s');
                    $msgData['type'] = 2;//消息数据
                    if (isset($data['to_id']) && $data['to_id'] > 0) {
                        $this->sendMessageByUid($data['to_id'], json_encode($msgData));//针对发送
                    } else {
                        $this->sendMessage(json_encode($msgData));//全局发送
                    }
                    break;
            }
        }
        $this->sendOnline();

    }

    public function onClose($connection) {
        if (isset($connection->uid)) {
            // 连接断开时删除映射
            unset(self::$uidConnections[$connection->uid]);
            $this->sendOnline();
        }
    }

    // 向所有验证的用户推送数据
    public function sendMessage($message) {
        foreach (self::$uidConnections as $connection) {
            $connection->send($message);
        }
    }

    // 针对uid推送数据
    public function sendMessageByUid($uid, $message) {
        if (isset(self::$uidConnections[$uid])) {
            $connection = self::$uidConnections[$uid];
            $connection->send($message);
            return true;
        }
        return false;
    }

    /**
     * 获取在线用户列表
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function sendOnline() {
        $MasterModel = new MasterModel();
        $master_list = $MasterModel->where('status=1')->field('uid,nickname,avatar')->select()->toArray();
        $connects = self::$uidConnections;
        $list['type'] = 1;//页面数据
        $list['list'] = [];
        foreach ($master_list as $v) {
            $v['online'] = isset($connects[$v['uid']]) ? 1 : 0;
            $list['list'][] = $v;
        }
        if (self::$master !== $list) {
            self::$master = $list;
            $this->sendMessage(json_encode($list));
        }

    }
}
